from flask import Flask, jsonify, request, abort
from apscheduler.schedulers.background import BackgroundScheduler
import subprocess
import json
import os
import requests
from bs4 import BeautifulSoup
from sparkai.llm.llm import ChatSparkLLM, ChunkPrintHandler
from sparkai.core.messages import ChatMessage
import random
import threading
import time

app = Flask(__name__)
app.config['CORS_HEADERS'] = 'Content-Type'

# 创建调度器
scheduler = BackgroundScheduler()

def update_news_and_pictures():
    """调用 new.py 和 picture.py 更新新闻和图片内容"""
    subprocess.run(['python', 'new.py'])
    subprocess.run(['python', 'picture.py'])

def read_json_file(file_path):
    """读取JSON文件内容"""
    if not os.path.exists(file_path):
        return []
    with open(file_path, 'r', encoding='utf-8') as f:
        return json.load(f)

@app.route('/news/<int:page>', methods=['GET'])
def news(page):
    items_per_page = 10
    start_index = (page - 1) * items_per_page
    end_index = start_index + items_per_page
    news_items = read_json_file('news_items.json')

    # 确保索引不会超出列表长度
    paginated_news = news_items[start_index:end_index] if start_index < len(news_items) else []

    return jsonify(paginated_news)

@app.route('/picture/<int:page>', methods=['GET'])
def picture(page):
    items_per_page = 10
    start_index = (page - 1) * items_per_page
    end_index = start_index + items_per_page
    picture_items = read_json_file('picture_item.json')

    # 确保索引不会超出列表长度
    paginated_pictures = picture_items[start_index:end_index] if start_index < len(picture_items) else []

    return jsonify(paginated_pictures)

def fetch_content_from_url(url):
    """从给定的URL中抓取特定class的内容，并提取img、p、h2和a标签的内容"""
    try:
        # 检查URL是否以http或https开头，如果没有则添加https://starwalk.space/
        if not url.startswith(('http://', 'https://')):
            url = f"https://starwalk.space/{url}"

        response = requests.get(url)
        response.raise_for_status()  # 如果响应状态码不是200，抛出异常
        soup = BeautifulSoup(response.text, 'html.parser')

        # 查找所有class为x6h6yq4的div元素
        elements = soup.find_all('div', class_='x6h6yq4')
        content_list = []

        for element in elements:
            item = []
            # 提取所有子元素
            for child in element.descendants:
                if child.name == 'img':
                    item.append({'tag': 'img', 'src': child.get('src')})
                elif child.name == 'p':
                    item.append({'tag': 'p', 'text': child.get_text(strip=True)})
                elif child.name == 'h2':
                    item.append({'tag': 'h2', 'text': child.get_text(strip=True)})
                elif child.name == 'a':
                    item.append({'tag': 'a', 'href': child.get('href'), 'text': child.get_text(strip=True)})
                elif child.name == 'h3':
                    item.append({'tag': 'h3', 'text': child.get_text(strip=True)})
                elif child.name == 'ul':
                    # 提取ul中的li标签内容
                    li_items = []
                    for li in child.find_all('li'):
                        li_items.append({'tag': 'li', 'text': li.get_text(strip=True)})
                    item.append({'tag': 'ul', 'items': li_items})

            content_list.append(item)

        return content_list
    except requests.RequestException as e:
        print(f"Error fetching URL: {e}")
        return []

@app.route('/fetch-content', methods=['POST'])
def fetch_content():
    """接收前端发送的URL，抓取内容并返回JSON"""
    data = request.get_json()
    url = data.get('url')
    if not url:
        return jsonify({"error": "URL is required"}), 400

    content = fetch_content_from_url(url)
    return jsonify(content)

# 星火认知大模型Spark Max的URL值，其他版本大模型URL值请前往文档（https://www.xfyun.cn/doc/spark/Web.html）查看
SPARKAI_URL = 'wss://spark-api.xf-yun.com/v1.1/chat'
# 星火认知大模型调用秘钥信息，请前往讯飞开放平台控制台（https://console.xfyun.cn/services/bm35）查看
SPARKAI_APP_ID = 'b4ae6555'
SPARKAI_API_SECRET = 'NmMzMmRiMDY4ODYzZjZiYjJlMTNiNWM2'
SPARKAI_API_KEY = '5d93206e67d7d722c7c3c60fd47c3e08'
# 星火认知大模型Spark Max的domain值，其他版本大模型domain值请前往文档（https://www.xfyun.cn/doc/spark/Web.html）查看
SPARKAI_DOMAIN = 'lite'

spark = ChatSparkLLM(
    spark_api_url=SPARKAI_URL,
    spark_app_id=SPARKAI_APP_ID,
    spark_api_key=SPARKAI_API_KEY,
    spark_api_secret=SPARKAI_API_SECRET,
    spark_llm_domain=SPARKAI_DOMAIN,
    streaming=False,
)


@app.route('/chat', methods=['POST'])
def chat():
    """接收前端发送的聊天消息，使用讯飞星火认知大模型生成回复"""
    data = request.get_json()
    user_message = data.get('message')
    if not user_message:
        return jsonify({"error": "Message is required"}), 400

    # 添加提示语句
    system_message = "我是青少年，请用易懂有趣味的语言"

    messages = [
        ChatMessage(
            role="system",
            content=system_message
        ),
        ChatMessage(
            role="user",
            content=user_message
        )
    ]

    handler = ChunkPrintHandler()
    response = spark.generate([messages], callbacks=[handler])

    # 提取生成的文本
    generated_text = response.generations[0][0].text

    return jsonify({"response": generated_text})

# 加载题目库
with open('questions.json', encoding='utf-8') as f:
    questions_db = json.load(f)

# 用户成绩存储
try:
    with open('scores.json', encoding='utf-8') as f:
        scores = json.load(f)
except FileNotFoundError:
    scores = {}

# 用户活动跟踪
user_activity = {}


def save_questions():
    with open('questions.json', 'w', encoding='utf-8') as f:
        json.dump(questions_db, f, ensure_ascii=False, indent=4)


def save_scores(scores, force=False):
    try:
        with open('scores.json', 'r', encoding='utf-8') as f:
            content = f.read().strip()
            if content:
                existing_scores = json.loads(content)
                print(f"Scores read from scores.json: {existing_scores}")  # 调试信息：打印从 scores.json 中读取的分数信息
            else:
                existing_scores = {}
        print(f"Existing scores before update: {existing_scores}")  # 调试信息：打印现有分数
    except FileNotFoundError:
        existing_scores = {}
        print("scores.json not found, initializing with empty scores.")  # 调试信息：文件未找到

    for username, score_info in scores.items():
        if force or (username not in existing_scores or score_info['score'] >= existing_scores[username]['score']):
            existing_scores[username] = score_info
        elif username in existing_scores:
            # 如果用户已经存在，确保更新头像
            existing_scores[username]['userimg'] = score_info.get('userimg', existing_scores[username].get('userimg', ''))

    print(f"Scores to be saved: {existing_scores}")  # 调试信息：打印将要保存的分数

    with open('scores.json', 'w', encoding='utf-8') as f:
        json.dump(existing_scores, f, ensure_ascii=False, indent=4)


@app.route('/get_question', methods=['POST'])
def get_question():
    data = request.get_json()
    username = data.get('username')
    userimg = data.get('userimg')  # 获取用户头像
    print('用户名：' + username)
    user_activity[username] = time.time()  # 更新用户活动时间

    if data.get('isFirstRequest') == True:
        for q in questions_db:
            q['used'] = False
        save_questions()
        scores[username] = {'score': 0, 'userimg': userimg}  # 初始化用户头像

    if username not in scores:
        scores[username] = {'score': 0, 'userimg': userimg}  # 初始化用户头像

    unanswered_questions = [q for q in questions_db if not q.get('used', False)]
    if not unanswered_questions:
        # 重置所有问题的 used 属性为 False
        for q in questions_db:
            q['used'] = False
        save_questions()
        return jsonify({"question": "所有问题都已回答", "options": []})

    question = random.choice(unanswered_questions)
    question_index = questions_db.index(question)
    questions_db[question_index]['used'] = True
    save_questions()

    # 返回问题和选项，但不包括正确答案
    response_question = {
        "question": question["question"],
        "options": question["options"]
    }

    # 保存当前用户的分数和头像
    save_scores({username: scores[username]})
    print(f"用户 {username} 当前分数和头像保存成功: {scores[username]}")  # 调试信息：打印当前保存的分数和头像

    return jsonify(response_question)


@app.route('/submit_answer', methods=['POST'])
def submit_answer():
    data = request.get_json()
    username = data.get('username')
    answer = data.get('answer')
    current_question_text = data.get('current_question')

    user_activity[username] = time.time()  # 更新用户活动时间

    # 增加调试信息
    print(f"Current question text: {current_question_text}")

    # 如果 current_question_text 为空，则直接出题
    if not current_question_text:
        print(f"current_question_text is empty, directly getting a new question for user {username}")
        return get_question()

    current_question = next((q for q in questions_db if q['question'] == current_question_text), None)
    print(f"Current question: {current_question}")  # 增加调试信息

    if current_question is None:
        return jsonify({"error": "Question not found"}), 400  # 返回错误信息

    correct_answer = current_question['correctAnswer']
    question_index = questions_db.index(current_question)

    if answer == correct_answer:
        questions_db[question_index]['used'] = True

    if answer != correct_answer:
        for q in questions_db:
            q['used'] = False
        save_questions()
        if username in scores:
            user_score = scores[username]['score']
        else:
            user_score = 0
        scores[username] = {'score': user_score, 'userimg': scores[username].get('userimg', '')}  # 保持分数不变并更新头像
        save_scores({username: scores[username]})
        return jsonify({'status': 'wrong', 'message': '游戏结束', 'score': user_score})

    unanswered_questions = [q for q in questions_db if not q.get('used', False)]
    if not unanswered_questions:
        scores[username] = {'score': len(questions_db), 'userimg': scores[username].get('userimg', '')}  # 假设每题1分并更新头像
        user_score = scores[username]['score']
        save_scores({username: scores[username]}, force=True)  # 强制保存分数
        return jsonify({'status': 'completed', 'message': '所有问题都已正确回答', 'score': user_score})

    if username not in scores:
        scores[username] = {'score': 0, 'userimg': ''}  # 初始化用户头像为空
    scores[username]['score'] += 1
    scores[username]['userimg'] = data.get('userimg', scores[username].get('userimg', ''))  # 更新头像
    save_scores({username: scores[username]})  # 传递 scores
    current_score = scores[username]['score']
    return jsonify({'status': 'right', 'score': current_score})


@app.route('/top_scores', methods=['GET'])
def top_scores():
    # 读取 scores.json 文件
    try:
        with open('scores.json', encoding='utf-8') as f:
            scores = json.load(f)
    except FileNotFoundError:
        scores = {}

    # 将 scores 字典转换为列表并按分数排序
    top_users = sorted(scores.items(), key=lambda x: x[1]['score'], reverse=True)[:10]

    # 返回分数最高的前十位用户及其分数和头像
    return jsonify([{'username': user[0], 'score': user[1]['score'], 'userimg': user[1].get('userimg', '')} for user in top_users])


@app.route('/query_score/<username>', methods=['GET'])
def query_score(username):
    """根据用户名从scores.json中查询对应的分数"""
    try:
        with open('scores.json', encoding='utf-8') as f:
            scores = json.load(f)
    except FileNotFoundError:
        scores = {}

    if username in scores:
        return jsonify({'username': username, 'score': scores[username]['score'], 'userimg': scores[username].get('userimg', '')})
    else:
        abort(404, description="找不到该用户")


if __name__ == '__main__':
    # 设置每天凌晨1点执行更新任务
    scheduler.add_job(func=update_news_and_pictures, trigger="cron", hour=1)
    scheduler.start()

    try:
        app.run(host='0.0.0.0', port=8080)
    except (KeyboardInterrupt, SystemExit):
        # 关闭调度器
        scheduler.shutdown()
